package pl.koziolekweb.translator.utilites;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.log4j.Logger;

/**
 * 
 * @author koziolek
 * 
 * 
 */
// Info: $Id$
public abstract class Context {

	/**
	 * 
	 */
	private static final String PROPERTIES_TRANSLATOR_CONFIGURATION_PROPERTIES = ""
			+ "properties-translator.configuration.properties";
	/**
	 * 
	 */
	private static Map<String, Object> properties = new HashMap<String, Object>();

	/**
	 * 
	 */
	private static Logger logger = Logger.getRootLogger();

	/**
	 * 
	 */
	private static final Context CONTEXT = new Context() {
	};

	/**
	 * 
	 * @param key
	 * @return
	 */
	public Object getObject(final String key) {
		return Context.properties.get(key);
	}

	/**
	 * @param key
	 * @return
	 */
	public String getParam(final String key) {
		Object ret = Context.properties.get(key);
		if (ret == null) {
			return null;
		}
		return ret.toString();
	}

	/**
	 * @param key
	 * @param value
	 * @return
	 */
	public Object add(final String key, final Object value) {
		return Context.properties.put(key, value);
	}

	/**
	 * Tworzy kontekst aplikacji.
	 * 
	 * @param files
	 *            lista plików z kontekstem.
	 * @return {@link Context } - aktualny kontekst aplikacji.
	 */
	public static Context getApplicationContext(final File... files) {
		if("true".equals(System.getProperty("run_as_maven"))){
			return Context.CONTEXT;
		}
		File configuration = null;
		if (files.length == 0) {
			configuration = Context.getConfigurationFile(new File("."));
		} else {
			configuration = Context.getConfigurationFile(files);
		}
		if (configuration == null) {
			throw new RuntimeException("NULL configuration exception");
		}
		try {
			Context.configure(new File(configuration.getAbsolutePath()));
		} catch (final FileNotFoundException e) {
			e.printStackTrace();
		} catch (final IOException e) {
			e.printStackTrace();
		}
		return Context.CONTEXT;
	}

	/**
	 * Zwraca kontekst aplikacji.
	 * 
	 * @return {@link Context} - aktualny kontekst aplikacji.
	 */
	public static Context getApplicationContext() {
		if (Context.CONTEXT != null) {
			return Context.getApplicationContext(new File("."));
		} else {
			return Context.CONTEXT;
		}
	}

	/**
	 * Tworzy konfigurację.
	 * 
	 * @param configuration
	 *            Plik konfiguracyjny.
	 * @throws FileNotFoundException
	 *             bark pliku konfiguracyjnego.
	 * @throws IOException
	 *             Problem IO.
	 */
	private static void configure(final File configuration) throws FileNotFoundException, IOException {
		final Properties properties = new Properties();
		properties.load(new FileReader(configuration));
		Context.properties.put("application.lang", "" + properties.get("application.lang"));
		Context.properties.put("enabled.lang", "" + properties.get("enabled.lang"));
		Context.properties.put("width", "" + properties.get("width"));
		Context.properties.put("height", "" + properties.get("height"));
		Context.properties.put("application.lang.path", "" + properties.get("application.lang.path"));
		Context.properties.put("gui.main.service.name", "" + properties.get("gui.main.service.name"));
		Context.loadDefault();
		final Properties language = new Properties();
		File langFile = new File(Context.properties.get("application.lang.path") + "labels_"
				+ Context.properties.get("application.lang") + ".properties");
		FileReader reader = new FileReader(langFile);
		language.load(reader);
		Context.properties.putAll(Context.toMap(language));
		Context.properties.put("logger", Context.logger);
		Context.logConfiguration();
	}

	private static void logConfiguration() {
		Context.logger.debug("Konfiguracja:");
		for (String key : Context.properties.keySet()) {
			Context.logger.debug("" + key + " : " + Context.properties.get(key));
		}
	}

	/**
	 * @param files
	 * @return
	 */
	private static File getConfigurationFile(final File... files) {
		File search = null;
		for (final File f : files) {
			search = Context.search(f);
			if (search == null) {
				continue;
			} else {
				break;
			}
		}
		return search;
	}

	/**
	 * Sprawdza czy plik jest plikiem konfiguracyjnym.
	 * 
	 * @param file
	 *            plik do spradzenia
	 * @return plik jeżeli konfiguracyjny w przeciwnym wypadku <b>null</b>.
	 */
	private static File isConfigurationFile(final File file) {
		if (Context.PROPERTIES_TRANSLATOR_CONFIGURATION_PROPERTIES.equals(file.getName())) {
			return file;
		} else {
			return null;
		}
	}

	/**
	 * ładuje domyślne ustawienia.
	 * 
	 * @throws FileNotFoundException
	 *             brak pliku konfiguracyjnego.
	 * @throws IOException
	 *             Problem IO.
	 */
	private static void loadDefault() throws FileNotFoundException, IOException {
		final Properties language = new Properties();
		language.load(new FileReader(new File(Context.properties.get("application.lang.path") + "labels"
				+ ".properties")));
		Context.properties.putAll(Context.toMap(language));

	}

	/**
	 * Przetwarza katalog.
	 * 
	 * @param file
	 *            Katalog.
	 * @return plik stawień.
	 */
	private static File proccedDir(final File file) {
		for (final File child : file.listFiles()) {
			final File search = Context.search(child);
			if (search == null) {
				continue;
			} else {
				return search;
			}
		}
		return null;
	}

	/**
	 * Metoda poszukuje pliku konfiguracyjnego.
	 * 
	 * @param file
	 *            aktualny katalog.
	 * @return plik konfiguracyjny.
	 */
	private static File search(final File file) {
		if (file.isDirectory()) {
			return Context.proccedDir(file);
		} else {
			return Context.isConfigurationFile(file);
		}
	}

	/**
	 * Zamienia obiekt {@link Properties} na {@link Map}.
	 * 
	 * @param properties
	 *            obiekt właściwości
	 * @return mapa właściwości.
	 */
	private static Map<? extends String, ? extends String> toMap(final Properties properties) {
		final Map<String, String> ret = new HashMap<String, String>();
		for (final Object key : properties.keySet()) {
			ret.put("" + key, "" + properties.get(key));
		}
		return ret;
	}
}
